<template>
	<div class="cl-upload-space__wrap">
		<slot>
			<el-button size="mini" @click="open">点击上传</el-button>
		</slot>

		<!-- 弹框 -->
		<cl-dialog :visible.sync="visible" v-bind="props">
			<div class="cl-upload-space">
				<!-- 类目 -->
				<div class="cl-upload-space__category">
					<div class="cl-upload-space__category-search">
						<el-button type="primary" size="mini" @click="editCategory()"
							>添加分类</el-button
						>
						<el-input
							v-model="category.keyword"
							placeholder="输入关键字过滤"
							size="mini"
						></el-input>
					</div>

					<div class="cl-upload-space__category-list">
						<ul>
							<li
								v-for="(item, index) in categoryList"
								:key="index"
								:class="{
									'is-active': item.id == category.current.id
								}"
								@click="selectCategory(item)"
								@contextmenu.stop.prevent="openCategormContextMenu($event, item)"
							>
								{{ item.name }}
							</li>
						</ul>
					</div>
				</div>

				<!-- 内容 -->
				<div class="cl-upload-space__content">
					<!-- 操作栏 -->
					<div class="cl-upload-space__opbar">
						<el-button
							type="success"
							size="mini"
							:disabled="selection.length === 0"
							@click="confirmPic()"
							>使用选中图片</el-button
						>
						<el-button
							type="danger"
							size="mini"
							:disabled="selection.length === 0"
							@click="deletePic()"
							>删除选中图片</el-button
						>

						<el-upload
							v-bind="upload.props"
							:style="{
								'margin-left': '10px'
							}"
						>
							<el-button type="primary" size="mini">上传图片</el-button>
						</el-upload>
					</div>

					<!-- 图片列表 -->
					<div
						class="cl-upload-space__image"
						v-loading="pics.loading"
						element-loading-text="拼命加载中"
					>
						<el-row v-if="pics.list.length > 0">
							<el-col :span="6" v-for="(item, index) in pics.list" :key="index">
								<div
									class="cl-upload-space__image-item"
									@click="selectPic(item)"
									@contextmenu.stop.prevent="openPicContextMenu($event, item)"
								>
									<!-- 图片 -->
									<el-image
										fit="cover"
										:src="item.url"
										lazy
										class="cl-upload-space__image-cover"
									></el-image>

									<!-- 尺寸 -->
									<div class="cl-upload-space__image-size"></div>

									<!-- 遮罩层 -->
									<div class="cl-upload-space__image-mask" v-show="item.selected">
										<i class="el-icon-success"></i>
									</div>
								</div>
							</el-col>
						</el-row>

						<div class="cl-upload-space__image-empty" v-else>
							<el-upload drag v-bind="upload.props">
								<i class="el-icon-upload"></i>
								<div class="el-upload__text">
									暂无图片，将文件拖到此处，或<em>点击上传</em>
								</div>
							</el-upload>
						</div>
					</div>

					<!-- 分页 -->
					<el-pagination
						background
						:page-size="pics.pagination.size"
						:current-page="pics.pagination.page"
						:total="pics.pagination.total"
						@current-change="onCurrentChange"
					></el-pagination>
				</div>
			</div>
		</cl-dialog>

		<!-- 右键菜单 -->
		<cl-context-menu ref="context-menu"></cl-context-menu>

		<!-- 添加分类 -->
		<cl-form ref="form-category"></cl-form>
	</div>
</template>

<script>
import { mapGetters } from "vuex";
import _ from "lodash";

export default {
	props: {
		multiple: Boolean,
		limit: {
			type: Number,
			default: 9
		}
	},

	data() {
		return {
			visible: false,
			props: {
				title: "图片空间",
				props: {
					"close-on-click-modal": false,
					width: "1000px"
				}
			},
			upload: {
				props: {
					action: "",
					headers: {
						Authorization: this.token
					},
					"show-file-list": false,
					multiple: true,
					accept: "image/*",
					"http-request": this.httpRequest
				}
			},
			category: {
				list: [],
				current: {},
				keyword: ""
			},
			pics: {
				list: [],
				pagination: {
					page: 1,
					size: 12,
					total: 0
				},
				loading: false
			}
		};
	},

	computed: {
		...mapGetters(["token"]),

		categoryList() {
			return this.category.list.filter((e) => e.name.includes(this.category.keyword));
		},

		selection() {
			return this.pics.list.filter((e) => e.selected);
		}
	},

	created() {
		this.refreshCategory().then(() => {
			this.category.current = this.category.list[0];
			this.refreshPic();
		});
	},

	methods: {
		open() {
			this.visible = true;
		},

		close() {
			this.visible = false;
		},

		// 重设上传方法
		httpRequest(req) {
			this.$service.common.ossUpload(req.file).then((url) => {
				this.$service.space.info
					.add({
						url,
						type: 0,
						classifyId: this.category.current.id
					})
					.then(() => {
						this.refreshPic();
					});
			});
		},

		// 刷新图片
		refreshPic(params) {
			this.pics.loading = true;

			this.$service.space.info
				.page({
					...this.pics.pagination,
					...params
				})
				.then((res) => {
					this.pics.list = res.list;
					this.pics.pagination = res.pagination;
				})
				.done(() => {
					this.pics.loading = false;
				});
		},

		// 刷新分类
		refreshCategory() {
			return this.$service.space.type.list().then((res) => {
				res.unshift({
					name: "全部图片",
					id: null
				});
				this.category.list = res;
			});
		},

		// 编辑分类
		editCategory(item = {}) {
			this.$refs["form-category"].open({
				props: {
					title: "添加分类",
					width: "400px"
				},

				items: [
					{
						label: "分类名称",
						prop: "name",
						value: item.name,
						component: {
							name: "el-input",
							attrs: {
								placeholder: "请填写分类名称"
							}
						},
						rules: {
							required: true,
							message: "分类名称不能为空"
						}
					}
				],

				on: {
					submit: (data, { done, close }) => {
						let next = null;

						if (!item.id) {
							next = this.$service.space.type.add(data);
						} else {
							next = this.$service.space.type.update({
								...data,
								id: item.id
							});
						}

						next.then(() => {
							this.refreshCategory();
							close();
						}).catch((err) => {
							this.$message.error(err);
							done();
						});
					}
				}
			});
		},

		// 选择类目
		selectCategory(item) {
			this.category.current = item;
			this.pics.pagination = {
				page: 1,
				size: 12,
				total: 0
			};
			this.refreshPic({
				classifyId: item.id
			});
		},

		// 打开类目列表右键菜单
		openCategormContextMenu(e, { id, name }) {
			if (!id) {
				return false;
			}

			this.$refs["context-menu"].open(e, {
				list: [
					{
						label: "编辑",
						"suffix-icon": "el-icon-edit",
						callback: (item, done) => {
							done();
							this.editCategory({ id, name });
						}
					},
					{
						label: "删除",
						"suffix-icon": "el-icon-delete",
						callback: (item, done) => {
							done();

							this.$confirm(
								`此操作将删除【${name}】下的图片文件, 是否继续?`,
								"提示",
								{
									type: "warning"
								}
							)
								.then(() => {
									this.$service.space.type
										.delete({
											ids: id
										})
										.then(() => {
											this.$message.success("删除成功");
											this.refreshCategory();
										})
										.catch((err) => {
											console.error(err);
											this.$message.error(err);
										});
								})
								.catch(() => {});
						}
					}
				]
			});
		},

		// 打开图片列表右键菜单
		openPicContextMenu(e, data) {
			this.$refs["context-menu"].open(e, {
				list: [
					{
						label: data.selected ? "取消选中" : "选中",
						"suffix-icon": data.selected ? "el-icon-close" : "el-icon-check",
						callback: (item, done) => {
							this.selectPic(data);
							done();
						}
					},
					{
						label: "删除",
						"suffix-icon": "el-icon-delete",
						callback: (item, done) => {
							this.deletePic(data);
							done();
						}
					}
				]
			});
		},

		// 确认选中图片
		confirmPic() {
			const urls = this.selection.map((e) => e.url);
			this.$emit("input", this.multiple ? urls : urls[0]);
			this.close();
		},

		// 选择图片
		selectPic(item) {
			if (this.multiple) {
				this.$set(item, "selected", !item.selected);
			} else {
				if (!item.selected) {
					this.pics.list.map((e) => {
						this.$set(e, "selected", false);
					});
				}
				item.selected = !item.selected;
			}
		},

		// 删除选中图片
		deletePic(...selection) {
			if (_.isEmpty(selection)) {
				selection = this.selection;
			}

			this.$confirm("此操作将删除图片文件, 是否继续?", "提示", {
				type: "warning"
			})
				.then(() => {
					const ids = selection.map((e) => e.id);

					this.$service.space.info
						.delete({
							ids: ids.join(",")
						})
						.then(() => {
							this.$message.success("删除成功");
							this.refreshPic();
						})
						.catch((err) => {
							this.$message.error(err);
						});
				})
				.catch(() => {});
		},

		// 选择页
		onCurrentChange(i) {
			this.refreshPic({
				page: i
			});
		}
	}
};
</script>

<style lang="scss" scoped>
.cl-upload-space {
	display: flex;
	height: 520px;

	&__category {
		width: 250px;
		margin-right: 20px;

		&-search {
			display: flex;
			align-items: center;
			margin-bottom: 5px;

			.el-button {
				margin-right: 10px;
			}
		}

		&-list {
			overflow: hidden auto;

			ul {
				li {
					list-style: none;
					font-size: 14px;
					height: 40px;
					line-height: 40px;
					border-bottom: 1px dashed #eee;
					padding: 0 5px;
					cursor: pointer;

					&.is-active {
						color: #409eff;
					}
				}
			}
		}
	}

	&__content {
		flex: 1;
	}

	&__opbar {
		display: flex;
		align-items: center;
		margin-bottom: 10px;
	}

	&__image {
		height: calc(100% - 70px);
		overflow: hidden auto;

		&-item {
			height: 160px;
			width: 160px;
			margin-bottom: 10px;
			cursor: pointer;
			position: relative;
			border-radius: 3px;
			box-sizing: border-box;
			background-color: #f7f7f7;
		}

		&-cover {
			height: 100%;
			width: 100%;
		}

		&-size {
			position: absolute;
			bottom: 0;
			left: 0;
			background-color: rgba(0, 0, 0, 0.5);
		}

		&-mask {
			position: absolute;
			left: 0;
			top: 0;
			height: 100%;
			width: 100%;
			background-color: rgba(0, 0, 0, 0.5);
			display: flex;
			justify-content: center;
			align-items: center;

			i {
				font-size: 30px;
				color: #67c23a;
			}
		}

		&-empty {
			text-align: center;
			margin-top: 100px;
			display: flex;
			align-items: center;
			justify-content: center;
		}
	}
}
</style>
